package com.zx.mes.oauth2.hyl.security.server;

import com.zx.mes.oauth2.hyl.service.impl.RedisAuthorizationCodeServices;
import com.zx.mes.oauth2.hyl.service.impl.RedisClientDetailsService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

/**
 * 认证服务器配置(授权服务器配置)
 *
 * @author 华云龙
 * @date 2018-12-17
 */
@Log4j2
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    /**
     * 使用jwt或者redis<br>
     * 默认redis
     */
    @Value("${access_token.store-jwt:false}")
    private boolean storeWithJwt;

    /**
     * 认证管理器
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private RedisAuthorizationCodeServices redisAuthorizationCodeServices;
    @Autowired
    private RedisClientDetailsService redisClientDetailsService;

    @Autowired
    private JwtAccessTokenConverter accessTokenConverter;

    /**
     * 客户端配置<br>
     * 将client信息存储到oauth_client_details表里<br>
     * 并将数据缓存到redis
     *
     * @param clients 客户端配置对象
     * @throws Exception 异常
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        /// 优化一下，详细看下redisClientDetailsService这个实现类
        clients.withClientDetails(redisClientDetailsService);
        redisClientDetailsService.loadAllClientToCache();
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        /// 允许表单形式的认证
        security.allowFormAuthenticationForClients();
    }

    /**
     * 认证及token配置
     *
     * @param endpoints 端点配置
     * @throws Exception 异常
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(this.authenticationManager)
                .tokenStore(tokenStore)
                /// 授权码模式下,code存储
                .authorizationCodeServices(this.redisAuthorizationCodeServices);
        if (this.storeWithJwt) {
            endpoints.accessTokenConverter(this.accessTokenConverter);
        } else {
            /// 将当前用户信息追加到登录后返回的数据里
            endpoints.tokenEnhancer((oAuth2AccessToken, oAuth2Authentication) -> {
                log.debug(oAuth2AccessToken);
                /// 追加操作
                return oAuth2AccessToken;
            });
        }
    }
}
